5.1. Gateway Setup
In one glance
- You will: Run the host gateway and verify its protocol and health boundaries.
- You need: The developer handoff, a configured Gemini key, container knowledge, and a running Docker-compatible engine.
- Time: about 35 minutes, hands-on.
What are the prerequisites?
Install the platform tools and verify the container engine before starting the data plane.
mise run install
mise run install:platform
mise run doctor:gateway
These commands install contributor and platform dependencies but create no cluster. 1.2. Containers owns engine preparation. Keep the root .env Gemini key from Part I; no GCP project is required for this API-key path.
The host profile uses Gemini by default. Gemini is proprietary and requests consume provider quota. 5.4. Model Gateway includes the optional Ollama profile for learners who can run it.
How do you start the host data plane?
Start the read-only MCP service, then the gateway, then the A2A application in separate terminals.
From agents/python, start MCP:
mise run mcp:http
From the repository root, start the gateway:
mise run gateway:host
The task selects infra/agentgateway/host/config-gemini.yaml. The wrapper puts the provider key in a private runtime directory and mounts only that key file into the non-root container. It does not mount your .env or send the key through command-line arguments.
From agents/python, start the agent with the governed routes:
AGENT_MODEL_PROVIDER=openai-compatible \
AGENT_MODEL=gemini-3.5-flash \
AGENT_MCP_URL=http://127.0.0.1:3000/mcp \
OPENAI_BASE_URL=http://127.0.0.1:4000/v1 \
OPENAI_API_KEY=local-gateway \
mise run a2a
The gateway owns the real Gemini credential. local-gateway is a non-secret client marker for this loopback lab, not gateway authentication. The model name remains compatibility-pinned; the application transport changes from native Gemini to the gateway's OpenAI-compatible endpoint. Re-run behavior evaluations before claiming the two paths are equivalent.
The gateway publishes MCP :3000, A2A :3001, model :4000, metrics :15020, and readiness :15021 on 127.0.0.1. Raw MCP and A2A processes remain on :8000 and :8080. Do not replace the wrapper with a raw gateway binary in the quickstart: the wrapper owns the checked loopback boundary.
How do you verify the listeners?
Check discovery, metrics, and readiness without making a model request.
curl -fsS http://127.0.0.1:3001/.well-known/agent-card.json | jq '{name,url}'
curl -fsS http://127.0.0.1:15020/metrics | head
curl -fsS http://127.0.0.1:15021/healthz/ready
Expect AgentOps Agent, Prometheus text, and ready. Discovery proves that the application answers through the gateway; it does not prove Gemini access or tool-call quality. 5.2. MCP Gateway exercises read-tool policy, and 5.3. A2A Gateway sends the first interactive request.
A connection refusal means the listener is unavailable. A 502 means the gateway cannot reach an upstream. A provider 401 or 429 belongs to credential or quota diagnosis, not Kubernetes diagnosis. Keep credentials out of copied logs.
What does the host wrapper actually run?
The wrapper renders container addresses, mounts configuration read-only, and starts a digest-pinned gateway image (currently agentgateway 1.4.1; mise.toml owns the version).
docker_args=(
run
--pull missing
--user 65532:65532
--read-only
--cap-drop ALL
--security-opt no-new-privileges=true
--tmpfs "/tmp:rw,noexec,nosuid,nodev,size=16m,mode=1777"
--add-host "host.docker.internal:${host_alias_ip:-host-gateway}"
)
The gateway runs as UID/GID 65532 with a read-only root filesystem, dropped capabilities, no privilege escalation, and loopback-only published listeners. The private runtime directory is mode 0700; mounted configuration and key files are read-only. On native Linux, a bridge-address relay lets the container reach host-loopback MCP and A2A services. Gemini traffic goes outbound over HTTPS.
The wrapper injects metrics and readiness addresses and disables the administration listener. Kubernetes uses pod-local HTTP readiness probes; readiness is not an extra public Service port.
Read gateway-host.sh for lifecycle and relay details. The optional Ollama profile also relays the local model endpoint; the Gemini profile has no model-server prerequisite.
How do you start and stop a detached gateway?
Use the lifecycle tasks when you need your terminal back.
mise run gateway:host:start
mise run gateway:host:status
mise run gateway:host:logs
mise run gateway:host:stop
Stop the foreground MCP and A2A terminals with Ctrl-C when finished. gateway:host:stop removes the wrapper-owned container, relay, and private runtime files. Keep other applications' containers and processes intact.
What proves this page worked?
Run the deterministic composition smoke separately from any live provider exercise.
mise run smoke:host
It uses a fake model and temporary ports, verifies MCP, A2A, model translation, policy, CORS, and telemetry, then tears down its processes. It qualifies the shared host composition; it does not certify the new Gemini provider route. That route also requires a live read-only tool-result turn when you choose to use provider quota.
You are done when:
- The offline smoke passes and the manual discovery/readiness checks answer.
- You can identify which process holds the provider key and which endpoint the agent calls.
- You distinguish static configuration validation, fake-backed composition, and live Gemini behavior.
- Temporary services are stopped when you leave the exercise.
Continue to 5.2. MCP Gateway when gateway discovery and readiness answer.